/* SimpleWebView.m - An Web browser using UIWebView.
 *
 * Copyright (C) 2008 Yuuichi Teranishi
 *
 * Original code was found at iphonedev BBS.
 *
 * This file is derived from Stumbler, a program developed by iphone-wireless
 * project.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * published by the Free Software Foundation.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; If not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
#import "SimpleWebView.h"
#import "MainView.h"
#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>
#import <GraphicsServices/GraphicsServices.h>
#import <UIKit/UIView-Geometry.h>
#import <UIKit/UINavigationItem.h>
#import <UIKit/UIWebView.h>
#include <sys/stat.h>
#include <dirent.h>

#define UIMouseDown                     1
#define UIMouseDragged                1<<2  //within active area of control
#define UIMouseExitedDragged     1<<3  //move outside active area 
#define UIMouseEntered                  1<<4 //move crossed into active area
#define UIMouseExited                   1<<5 //move crossed out of active area
#define UIMouseUp                   1<<6 //up within the active area
#define UIMouseExitedUp              1<<7 //up outside active area


#define MIN_SCALE (1.0f)
#define MAX_SCALE (4.0f)
#define ZOOM_RATE (0.005f)

#define WORLD_HEIGHT 5000.0f
#define WORLD_WIDTH  5000.0f
#define SCREEN_HEIGHT 700.0f
#define SCREEN_WIDTH  700.0f


extern NSString *WebViewProgressEstimateChangedNotification;

@implementation SimpleWebView
-(void)loadHTML: (NSString *)html
{
  [webView loadHTMLString: html baseURL: nil];
}

-(void)loadURL: (NSURL *)url
{
  NSURLRequest* urlRequest = [NSURLRequest requestWithURL: url];
  currentUrl = url;
  [webView loadRequest: urlRequest];
  [[webView webView] setResourceLoadDelegate:self];
  [[webView webView] setFrameLoadDelegate:self];
  [[webView webView] setDownloadDelegate:self];
  [scroller setContentSize: CGSizeMake(WORLD_WIDTH, WORLD_HEIGHT)];
}

-(void)view: (UIView*)v didSetFrame:(CGRect)f
{
  //  if( v == webView )
    //    [self setContentSize: CGSizeMake(f.size.width, f.size.height)];
    //    [self setContentSize: CGSizeMake(1000, 1000)];
}

- (void) resizeImage: (float) zoom
{
  [webView zoomToScale: zoom];
}

- (void)mouseDragged:(GSEventRef)theEvent
{
  [super mouseDragged:theEvent];
}

-(void)dealloc
{
	[webView release];
	[super dealloc];
}

-(NSString *)execJavaScriptOnCurrentThread:(NSString *)script {
  return [[webView webView]
	   stringByEvaluatingJavaScriptFromString: script];
}

-(void)execJavaScript:(NSString *)script
{
  [ self performSelectorOnMainThread: @selector(execJavaScriptOnCurrentThread:)
	 withObject: script waitUntilDone:YES ];
}

-(BOOL)loaded
{
  return loaded;
}

- (void)setTapDelegate:(id)delegate {
  _tapDelegate = delegate;
}

// - (void)mouseDragged:(GSEventRef)event
// {
//   // Currently not used..
//   if (lastX != -1 && lastY != -1) 
//     {
//       [_tapDelegate draggedWithX: (int)(event->x - lastX)
// 			  withY: (int)(event->y - lastY)];
//     }
//   lastX = event->x;
//   lastY = event->y;
// }

- (void)view:(UIView *)view handleTapWithCount:(int)count event:(GSEvent *) event fingerCount: (int)finger
{ 
  if (count == 2) {
    if (finger == 1) {
      [_tapDelegate webDoubleTapped];
    }
  }
}

- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
{
  [ webDelegate simpleWebView: self loadFinished: currentUrl ];
  loaded = YES;
}

+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector { return NO; }

- (void)webView:(WebView *)sender windowScriptObjectAvailable:(id)windowScriptObject
{
  // add the key-value notification object to the script environment
  [windowScriptObject setValue:self forKey:@"webview"];
}

- (void) webView: (WebView*)webView addMessageToConsole: (NSDictionary*)dictionary
{
  NSLog(@"Javascript log: %@", dictionary);
}

- (BOOL) fileExists: (NSString *)file {
  struct stat s;
  if (stat([file cStringUsingEncoding: NSUTF8StringEncoding], &s) < 0) { 
    return NO;
  }
  return YES;
}

- (NSString *) encodeURLString:(NSString *) string
{
  NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding
			 allowLossyConversion:YES];

  unsigned char  *ptr = (unsigned char *)[data bytes];
  unsigned char  *maxPtr = ptr + [data length];
  unsigned char  *buffer = malloc([data length]*5);
  unsigned char  *target = buffer;
  char *hexChars = "0123456789ABCDEF";
  char *unsafechars = " <>[]^`|{}\\/";
  int targetLen=0;
  id retObject;

  while( ptr < maxPtr )
    {
      if( *ptr < 0x20  ||  strchr( unsafechars, *ptr ) ||  *ptr >= 0x7f )
	{
	  *target++ = '%';
	  *target++ = hexChars[  *ptr / 16 ];
	  *target++ = hexChars[  *ptr % 16 ];
	  targetLen +=3;
	}
      else
	{
	  *target++ = *ptr;
	  targetLen ++;
	}
      ptr ++;
    }
  *target = '\0';
  
  retObject = [NSString stringWithCString:(char *)buffer];
  free(buffer);
  return retObject;
} 

- (void)alertSheet:(UIAlertSheet*)sheet buttonClicked:(int)button {
  if ( button == 1 ) {
    [self clearCacheFilesExecute];
    NSLog(@"removed.");
  }
  [sheet dismiss];
}


- (int) clearCacheFiles {
  NSArray *buttons = [NSArray arrayWithObjects:@"OK", @"Cancel", nil];
  UIAlertSheet *alertSheet = [[UIAlertSheet alloc] initWithTitle:@"Alert" buttons:buttons defaultButtonIndex:1 delegate:self context:self];
  [alertSheet setBodyText:@"Remove all cache files?"];
  [alertSheet popupAlertAnimated:YES];
}

- (int) clearCacheFilesExecute {
  struct dirent* dp;
  DIR* dirp;
  int num = 0;
  NSString *cacheDir = @"/var/mobile/iSpotter/cache";
  
  if ((dirp = opendir([cacheDir cStringUsingEncoding: NSUTF8StringEncoding])) == NULL)
    NSLog(@"Error opening cache directory");
  while ((dp = readdir(dirp)) != NULL) {
    if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0) {
      num++;
      char *path = [[cacheDir stringByAppendingPathComponent:
				[NSString stringWithCString: dp->d_name
					  encoding: NSUTF8StringEncoding]]
		     cStringUsingEncoding: NSUTF8StringEncoding];
      unlink(path);
    }
  }
  closedir(dirp);
  return num;
}

- (NSString *) cachePathForURL: (NSURL *) url {
  NSString *sFoldPath = @"/var/mobile/iSpotter/cache";
  NSString *encoded = nil;
  NSRange range = [[url absoluteString] rangeOfString: @"verify"];
  NSRange range2 = [[url absoluteString] rangeOfString: @"jsapi"];
  NSRange range3 = [[url absoluteString] rangeOfString: @"spn"];
  
  if (range.length == 0 && range2.length == 0 && range3.length == 0) {
    encoded = [ sFoldPath stringByAppendingPathComponent :
			    [self encodeURLString:
				    [url absoluteString]]];
  }
  else if (range3.length != 0) {
    encoded = [ sFoldPath stringByAppendingPathComponent : @"spn"];
  }
  else if (range2.length != 0) {
    encoded = [ sFoldPath stringByAppendingPathComponent : @"jsapi"];
  }
  else {
    encoded = [ sFoldPath stringByAppendingPathComponent : @"verify"];
  }
  
  return encoded;
  //			 stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
}

- (void) webView : (WebView *) sender resource : (id) identifier didFinishLoadingFromDataSource : (id) dataSource { 
  if (preferences.caching) {
    NSCachedURLResponse *cResponse = [ [ NSURLCache sharedURLCache ] cachedResponseForRequest : identifier ];
    NSURLResponse *uResponse  = [ cResponse response ]; 
  
    if ( ![[ [ uResponse URL ] scheme] isEqualToString: @"file"]  ) { 
      if ((cResponse != nil) &&
	  (uResponse != nil) &&
	  ![[[ uResponse URL ] scheme] isEqualToString:@"file"] ) {
	NSString *path = [self cachePathForURL: [uResponse URL]];
	if (![self fileExists: path]) {
	  [ [ cResponse data ] writeToFile : path
			       atomically : YES ];
	}
      }
    }
  }
}

- (NSURLRequest *)webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(id)dataSource {
  if (preferences.caching) {
    if ((request != nil) &&
	![[[ request URL ] scheme] isEqualToString:@"file"] ) {
      if ([[[request URL] absoluteString]isEqualToString:@""]) {
	return request;
      }
      NSURL *url = [request URL];
      NSString *path = [self cachePathForURL: url];
      
      // force cache jsapi
      NSRange range = [[url absoluteString] rangeOfString: @"jsapi"];
      if (range.length != 0) {
	if (![self fileExists: path]){
	  // force cache jsapi
	  NSData *data = [self getWithURL: url];
	  NSLog(@"length=%d", [data length]);
	  if (data != nil) {
	    [ data writeToFile : path atomically : YES ];
	  }
	}
      }
      if ([self fileExists: path]){
	//	NSLog(@"HIT:%@", url);
	return [NSURLRequest requestWithURL:
			       [NSURL fileURLWithPath: path]
			     cachePolicy:NSURLRequestReturnCacheDataElseLoad
			     timeoutInterval:[request timeoutInterval]];
      }
      //      NSLog(@"MISS:%@", url);
      // miss
    }
    // [request setValue:@"public" forHTTPHeaderField:@"Cache-Control"];
  }
  return request;
}

- (id) webView : (WebView *) sender identifierForInitialRequest : (NSURLRequest  *) request fromDataSource : (id) dataSource {
  return( request );
}

- (NSData *) getWithURL: (NSURL *) url {
  NSURLResponse *resp;
  NSError *error;
  NSMutableURLRequest *req = [ NSMutableURLRequest requestWithURL : url ];

  NSLog(@"req=%@", req);
  return [NSURLConnection sendSynchronousRequest: req
			  returningResponse: &resp
			  error: &error];
}

- (void)gestureChanged: (GSEventRef)theEvent {
}

- (void)gestureEnded:(GSEvent *)event {
  if (event->numPoints == 1)  {
    // [_tapDelegate webDoubleTapped];
    //    NSLog( @"ended at (%f,%f)", event->x, event->y);
  }
  if (event->numPoints == 2)  {
    [_tapDelegate webTwoTapped];
  }
  else if (event->numPoints == 3) {
    [_tapDelegate webThreeTapped];
  }
}

- (BOOL)canHandleGestures {
  return YES; // for Gesture
}

- (void)scrollerWillStartDragging:(UIScroller*)scroller {
  if (scroll) {
    //    NSLog( @"drag started at (%f,%f)", [scroller offset].x,  [scroller offset].y );
    if (lastX == -1 && lastY == -1 ) {
      lastX = [scroller offset].x;
      lastY = [scroller offset].y;
    }
  }
}

- (void)scrollerDidEndDragging:(UIScroller*)scroller willSmoothScroll:(BOOL)flag {
  if (scroll) {
    //    NSLog( @"drag stopped at (%f,%f)", [scroller offset].x,  [scroller offset].y );
    CGPoint pt;
    CGSize navBarSize = [UINavigationBar defaultSize];
    pt.x = (WORLD_WIDTH / 2)  - (w / 2);
    pt.y = (WORLD_HEIGHT / 2) - (h / 2) + navBarSize.height;
    if (!flag) {
      if (lastX != -1 && lastY != -1) {
	[webDelegate simpleWebView:self
		     movedToX: (int)((SCREEN_WIDTH / 2) - (lastX - [scroller offset].x))
		     toY: (int)((SCREEN_HEIGHT / 2) - (lastY - [scroller offset].y))];
	//[scroller setOffset: pt];
      }
      lastX = -1;
      lastY = -1;
    }
  }
}

- (void)scrollerWillStartSmoothScrolling:(UIScroller*)scroller {
  if (scroll) {
    //    NSLog( @"start at (%f,%f)", [scroller offset].x,  [scroller offset].y );
    if (lastX == -1 && lastY == -1 ) {
      lastX = [scroller offset].x;
      lastY = [scroller offset].y;
    }
  }
}
	
- (void)scrollerDidEndSmoothScrolling:(UIScroller*)scroller {
  if (scroll) {
    CGPoint pt;
    CGSize navBarSize = [UINavigationBar defaultSize];
    //    NSLog( @"stopped at (%f,%f)", [scroller offset].x,  [scroller offset].y );
    pt.x = (WORLD_WIDTH / 2) - (w / 2);
    pt.y = (WORLD_HEIGHT / 2) - (h / 2) + navBarSize.height;
    if (lastX != -1 && lastY != -1) {
      [webDelegate simpleWebView:self 
		   movedToX: (int)((SCREEN_WIDTH / 2) - (lastX - [scroller offset].x))
		   toY: (int)((SCREEN_HEIGHT / 2) - (lastY - [scroller offset].y))];
      //[scroller setOffset: pt];
    }
    lastX = -1;
    lastY = -1;
  }
}

- (id) createCenterButton {
  CGSize navBarSize = [UINavigationBar defaultSize];
  UIPushButton *button =
    [[UIPushButton alloc] initWithFrame: CGRectMake(w / 2 - 15, h / 2 - 15 - navBarSize.height,
						    30.0f, 30.0f)];
  UIImage* on = [[UIImage alloc]
		  initWithContentsOfFile: @"/Applications/iSpotter.app/centerCross2.gif"];
  [button setImage:on forState:0];

  [button setEnabled:YES];
  [button setDrawContentsCentered:YES];
  [button setAutosizesToFit:YES];
  [button setNeedsDisplay];
  //  [button setShowPressFeedback:YES];
  // [button addTarget:self action:@selector(buttonEvent:) forEvents:UIMouseUp];
  return button;
}

- (id) createButton:(NSString *)name x:(float) x y:(float) y {
  CGSize navBarSize = [UINavigationBar defaultSize];
  UIPushButton *button =
    [[UIPushButton alloc] initWithFrame: CGRectMake(x, y, 35.0f, 35.0f)];
  UIImage* on = [[UIImage alloc]
		  initWithContentsOfFile:
		    [NSString stringWithFormat:
				@"/Applications/iSpotter.app/%@-on.png", name]];
  UIImage* off = [[UIImage alloc]
		  initWithContentsOfFile:
		    [NSString stringWithFormat:
				@"/Applications/iSpotter.app/%@-off.png", name]];
  [button setImage:on forState:1];
  [button setImage:off forState:0];

  [button setEnabled:YES];
  [button setDrawContentsCentered:YES];
  [button setAutosizesToFit:YES];
  [button setNeedsDisplay];
  [button setShowPressFeedback:YES];
  [button addTarget:self action:@selector(buttonEvent:) forEvents:UIMouseUp];
  return button;
}

- (void) buttonEvent:(UIPushButton *)button {
  if (button == zin) {
    [self execJavaScript: @"zoomIn()"];
  }
  else if (button == zout) {
    [self execJavaScript: @"zoomOut()"];
  }
  else if (button == cpos) {
    [self execJavaScript: @"moveTo(lastX, lastY, lastF)"];
  }
  else if (button == cv) {
    [self execJavaScript: @"changeView()"];
  }
  else if (button == det) {
    [self execJavaScript: @"detect()"];
  }

}

- (void)gotoFloor:(int)floor {
  [webDelegate gotoFloor: floor];
}

- (void)messageAreaExecJavaScript:(NSString *)script {
  [webDelegate messageAreaExecJavaScript: script];
}

- (void)detect {
  [webDelegate scan];
}

- (void)drawRect:(CGRect)rect
{
  // Draw background
  UIImage*    image;
  image = UIImageGetPinstripe();
  [image drawAsPatternInRect:rect];
}

-(void)gotoCenter {
  CGPoint pt;
  CGSize navBarSize = [UINavigationBar defaultSize];
  pt.x = (WORLD_WIDTH / 2) - (w / 2);
  pt.y = (WORLD_HEIGHT / 2) - (h / 2) + navBarSize.height;  
  [scroller setOffset: pt];
}

-(id)initWithFrame: (CGRect)frame webDelegate:(id)delegate withSmoothScroll:(BOOL) flag
{
  loaded = NO;
  webDelegate = delegate;
  lastX = -1;
  lastY = -1;

  CGRect screenRect = [UIHardware fullScreenApplicationContentRect];
  w = screenRect.size.width;
  h = screenRect.size.height;

  [super initWithFrame: frame];

  scroller = [[UIScroller alloc] initWithFrame: frame];

  [scroller setDirectionalScrolling: NO];
  [scroller setAllowsRubberBanding: NO];
  [scroller setShowScrollerIndicators: NO];
  [scroller setAllowsFourWayRubberBanding: NO];
  // [self setAdjustForContentSizeChange: YES];
  [scroller setClipsSubviews: YES];
  [scroller setDelegate: self];

  CGRect rect;
  CGPoint pt;

  if (flag) {
    // starting point;
    CGSize navBarSize = [UINavigationBar defaultSize];

    scroll = YES;
    pt.x = (WORLD_WIDTH / 2) - (w / 2);
    pt.y = (WORLD_HEIGHT / 2) - (h / 2) + navBarSize.height;
    //    NSLog( @"offset is (%f,%f)", pt.x, pt.y );

    [scroller setScrollingEnabled: YES];
    [scroller setAdjustForContentSizeChange: YES];

    rect = CGRectMake((WORLD_WIDTH - SCREEN_WIDTH) / 2,
		      (WORLD_HEIGHT - SCREEN_HEIGHT) / 2,
		      SCREEN_WIDTH, SCREEN_HEIGHT);
    [scroller setOffset: pt];
  }
  else {
    scroll = NO;

    [scroller setScrollingEnabled: NO];
    [scroller setAdjustForContentSizeChange: NO];
    rect = CGRectMake(0.0f, 0.0f, frame.size.width, frame.size.height) ;
  }

  webView = [[UIWebView alloc] initWithFrame: rect];
  [webView setAutoresizes: YES];
  [webView setDelegate: self];
  [webView setTapDelegate: self];

  // [self setEnabledGestures: 2];
  //  [webView zoomToScale: 0.5f];

  //  [webView setValue: [NSNumber numberWithBool: NO] forGestureAttribute: 7];
  //  [webView setValue: [NSNumber numberWithBool: NO] forGestureAttribute: 4];
  //  [webView setValue: [NSNumber numberWithBool: YES] forGestureAttribute: 5];

  WebView *mCoreWebView = [webView webView];
  [mCoreWebView setFrameLoadDelegate: self];
  [mCoreWebView setPolicyDelegate: self];
  [mCoreWebView setUIDelegate: self];
  [mCoreWebView setResourceLoadDelegate: self];

  [scroller addSubview: webView];
  [self addSubview: scroller];
  if (flag) {
    UIPushButton *button = [self createCenterButton];
    [self addSubview: button];

    det  = [self createButton:@"detect" x: 280 y:146];
    cv  = [self createButton:@"changeView" x: 280 y:183];
    zin = [self createButton:@"zoomIn" x: 280 y:220];
    zout = [self createButton:@"zoomOut" x: 280 y:257];
    cpos = [self createButton:@"curPos" x: 280 y:294];

    [self addSubview: det];
    [self addSubview: cv];
    [self addSubview: zin];
    [self addSubview: zout];
    [self addSubview: cpos];
    
  }

  return self;
}

@end
